package com.vichat.online.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.vichat.common.cache.RedisHelper;
import com.vichat.common.util.DateUtil;
import com.vichat.common.util.NumberUtils;
import com.vichat.core.dao.BaseDaoI;
import com.vichat.online.entity.OnlineUserDLog;
import com.vichat.online.entity.OnlineUserLog;
import com.vichat.online.entity.OnlineUserMLog;
import com.vichat.online.entity.StatOnlineUser;
import com.vichat.online.service.IOnlineService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.*;

@Service("onlineService")
public class OnlineServiceImpl implements IOnlineService {


    private static transient final Logger logger = LoggerFactory.getLogger(OnlineServiceImpl.class);
    @Autowired
    private BaseDaoI<StatOnlineUser> daoStatOnlineUser;

    @Autowired
    private BaseDaoI<OnlineUserMLog> onlineUserMLogDao;
    @Autowired
    private BaseDaoI<OnlineUserDLog> onlineUserDLogDao;
    @Autowired
    private BaseDaoI<OnlineUserLog> daoOnlineUserLog;

    @Override
    public HashMap<Long, StatOnlineUser> initOnlineUser() {
        HashMap<Long, StatOnlineUser> onlineRoomUser = new HashMap<Long, StatOnlineUser>();

        StringBuilder hql = new StringBuilder();
        hql.append("select count(*) from StatOnlineUser where state>0");
        Long totals = daoStatOnlineUser.count(hql.toString());
        int rows = 1000;
        long pages = totals / 1000;
        if (totals % 1000 > 0) {
            pages++;
        }
        logger.error("加载总用户数" + totals + ",加载次数" + pages);
        for (int page = 0; page < pages; page++) {
            List<StatOnlineUser> statOnlineUsers = daoStatOnlineUser.find("from StatOnlineUser where state > 0", new HashMap<String, Object>(), page + 1, rows);

            for (StatOnlineUser statOnlineUser : statOnlineUsers) {
                try {
                    statOnlineUser.setLastTime(statOnlineUser.getUpTime());
                    onlineRoomUser.put(statOnlineUser.getUid(), statOnlineUser);
                } catch (Exception e) {
                    logger.error("获取单个用户信息失败", e);
                }

            }

        }
        return onlineRoomUser;

    }

    public void dealUserOffline(StatOnlineUser statOnlineUser) throws Exception {

        // 找到在线数据，计算在线时长并更新
        if (statOnlineUser != null) {
            if (statOnlineUser.getLastTime().getTime() < System.currentTimeMillis() - 600000) {//如果上次更新时间和当前比大于10分钟，则离线时间认为是上次更新时间+10分钟；否则认为是当前时间
                statOnlineUser.setOutTime(DateUtil.addMinutes((Timestamp) statOnlineUser.getLastTime(), 10));
            } else {
                statOnlineUser.setOutTime(statOnlineUser.getLastTime());
            }

            statOnlineUser.setState(0L);
            daoStatOnlineUser.deleted(statOnlineUser);
            dealOnlineUserDLog(statOnlineUser.uid, statOnlineUser.getUpTime(), statOnlineUser.getOutTime());
        }

    }


    public void saveStatOnlineUser(StatOnlineUser newStatOnlineUser) throws Exception {


        // 找到在线数据，计算在线时长并更新
        StatOnlineUser oldStatOnlineUser = daoStatOnlineUser.get(StatOnlineUser.class, newStatOnlineUser.getUid());
        if (oldStatOnlineUser != null) {

            dealOnlineUserDLog(oldStatOnlineUser.uid, oldStatOnlineUser.getUpTime(), newStatOnlineUser.getUpTime());
            oldStatOnlineUser.setUpTime(newStatOnlineUser.getUpTime());
            oldStatOnlineUser.setImDisplayState(newStatOnlineUser.getImDisplayState());
            oldStatOnlineUser.setState(1L);
            daoStatOnlineUser.update(oldStatOnlineUser);
        } else {
            daoStatOnlineUser.save(newStatOnlineUser);

        }


    }


    public void dealOnlineUserDLog(long uid, Date oldTime, Date newTime) {
        try {
            boolean isSameDay = DateUtil.isSameDate(oldTime, newTime);
            if (isSameDay) {
                saveOnlineUserLog(uid, oldTime, newTime);
            } else {
                saveOnlineUserLog(uid, oldTime, DateUtil.todayStart());
                saveOnlineUserLog(uid, DateUtil.todayStart(), newTime);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }


    private void saveOnlineUserLog(long uid, Date startTime, Date endTime) {
        StringBuilder sql = new StringBuilder();
        long second = Math.round(Math.ceil((endTime.getTime() - startTime.getTime()) / 1000));
        long partyId = 0l;
        long orgId = 0l;
        String orgCode = "";
        String userBasiceStr = RedisHelper.getUser(uid);
        JSONObject obj = JSONObject.parseObject(userBasiceStr);
        if (obj != null) {
            if (obj.containsKey("partyId")) {
                partyId = obj.getLongValue("partyId");
            }
            if (obj.containsKey("orgId")) {
                orgId = obj.getLongValue("orgId");
            }
            if (obj.containsKey("orgCode")) {
                orgCode = obj.getString("orgCode");
            }
        }
        if (partyId > 0) {
            sql.append("insert into ").append(getOnlineUserDLogTable(startTime));
            sql.append(" (uid,party_id,org_id,org_code,start_time,end_time,second,state) values (:uid,:partyId,:orgId,:orgCode,:startTime,:endTime,:second,1)");
            HashMap params = new HashMap();
            params.put("uid", uid);
            params.put("startTime", startTime);
            params.put("endTime", endTime);
            params.put("second", second);
            params.put("partyId", partyId);
            params.put("orgId", orgId);
            params.put("orgCode", orgCode);
            onlineUserDLogDao.executeSql(sql.toString(), params);
        }
    }


    public static String getOnlineUserDLogTable(Date startTime) {
        return "onlinedb.online_user_d_log_" + DateUtil.getFormattedDate(startTime, "yyyyMMdd");
    }

    private String userMlogTablename(Date date) {
        String name = DateUtil.getYearMonth(date);
        return "onlinedb.online_user_m_log_" + name;
    }

    public void processOnlineUserLog(String today) {
        daoOnlineUserLog.executeSql("truncate table onlinedb.online_user_log");
        StringBuilder sql = new StringBuilder();
        sql.append("insert into onlinedb.online_user_log (uid,party_id,org_id,org_code,start_time,end_time,second,day,state) ");
        sql.append(" select uid,party_id,org_id,org_code,min(start_time),max(end_time),sum(second) as second,str_to_date('").append(today).append("','%Y%m%d') as day,1 from onlinedb.online_user_d_log_").append(today).append(" group by uid,party_id");
        logger.info(sql.toString());
        daoOnlineUserLog.executeSql(sql.toString());
    }

    public void processOnlineUserMLog(String yesterDayMonth, String yesterDay) {
        StringBuilder sql = new StringBuilder();
        sql.append("insert into onlinedb.online_user_m_log_").append(yesterDayMonth).append(" (uid,party_id,org_id,org_code,second,day,state)");

        sql.append(" select uid,party_id,org_id,org_code,sum(second) as second,str_to_date('").append(yesterDay).append("','%Y%m%d') as day,1 from onlinedb.online_user_d_log_").append(yesterDay).append(" group by uid,party_id");
        logger.info(sql.toString());
        onlineUserMLogDao.executeSql(sql.toString());
    }


    public boolean isExistOnlineUserMLog(String yesterDayMonth, String yesterDay) {
        StringBuilder sql = new StringBuilder();
        sql.append("select count(*) from onlinedb.online_user_m_log_").append(yesterDayMonth).append(" where day = :day");
        Date day = DateUtil.getDateByString(yesterDay, "yyyyMMdd");
        HashMap params = new HashMap();
        params.put("day", day);
        BigInteger count = onlineUserMLogDao.countBySql(sql.toString(), params);
        return count.longValue() > 0 ? true : false;
    }

    @Override
    public List<OnlineUserMLog> getOnlineUserMLogDayReport(long partyId) throws Exception {
        List<OnlineUserMLog> onlineUserMLogs = new ArrayList<>();
        String tableName = getOnlineUserDLogTable(DateUtil.getCalendarCurrentTimestamp());
        StringBuilder sql = new StringBuilder();
        sql.append(" select id,uid,party_id,org_id,org_code,sum(second) second,0 day,state from ").append(tableName).append(" where 1 = 1 ");
        sql.append(" and party_id=").append(partyId);
        sql.append(" GROUP BY uid ORDER BY second desc limit 20");
        List locationDataList = onlineUserMLogDao.findEntityBySql(sql.toString(), new HashMap(), OnlineUserMLog.class);
        for (Iterator iter = locationDataList.iterator(); iter.hasNext(); ) {
            try {
                OnlineUserMLog onlineUserMLog = (OnlineUserMLog) iter.next();
                onlineUserMLog.setUserName(RedisHelper.getUname(onlineUserMLog.getUid()));
                onlineUserMLogs.add(onlineUserMLog);
            } catch (Exception e) {
                logger.error("获取OnlineUserMLog当天排行榜失败", e);
            }
        }
        if (onlineUserMLogs.size() == 0) {
            return null;
        }
        return onlineUserMLogs;
    }

    @Override
    public List<OnlineUserMLog> getOnlineUserMLogWeekReport(long partyId) throws Exception {
        List<OnlineUserMLog> onlineUserMLogs = new ArrayList<>();
        String tableName = userMlogTablename(DateUtil.getCalendarCurrentTimestamp());
        StringBuilder sql = new StringBuilder();
        sql.append(" select id,uid,party_id,org_id,org_code,sum(second) second,day,state from ").append(tableName).append(" where 1 = 1 ");
        sql.append(" and DATE_FORMAT(CURDATE(), '%Y%u')=DATE_FORMAT(day, '%Y%u')");
        sql.append(" and party_id=").append(partyId);
        sql.append(" GROUP BY uid ORDER BY second desc limit 20");
        List locationDataList = onlineUserMLogDao.findEntityBySql(sql.toString(), new HashMap(), OnlineUserMLog.class);
        for (Iterator iter = locationDataList.iterator(); iter.hasNext(); ) {
            try {
                OnlineUserMLog onlineUserMLog = (OnlineUserMLog) iter.next();
                onlineUserMLog.setUserName(RedisHelper.getUname(onlineUserMLog.getUid()));
                onlineUserMLogs.add(onlineUserMLog);
            } catch (Exception e) {
                logger.error("获取OnlineUserMLog本周排行榜失败", e);
            }
        }
        if (onlineUserMLogs.size() == 0) {
            return null;
        }
        return onlineUserMLogs;
    }

    @Override
    public List<OnlineUserMLog> getOnlineUserMLogMonthReport(long partyId) throws Exception {
        List<OnlineUserMLog> onlineUserMLogs = new ArrayList<>();
        String tableName = userMlogTablename(DateUtil.getCalendarCurrentTimestamp());
        StringBuilder sql = new StringBuilder();
        sql.append(" select id,uid,party_id,org_id,org_code,sum(second) second,day,state from ").append(tableName).append(" where 1 = 1 ");
        sql.append(" and DATE_FORMAT(CURDATE(), '%Y%m')=DATE_FORMAT(day, '%Y%m')");
        sql.append(" and party_id=").append(partyId);
        sql.append(" GROUP BY uid ORDER BY second desc limit 20");
        List locationDataList = onlineUserMLogDao.findEntityBySql(sql.toString(), new HashMap(), OnlineUserMLog.class);
        for (Iterator iter = locationDataList.iterator(); iter.hasNext(); ) {
            try {
                OnlineUserMLog onlineUserMLog = (OnlineUserMLog) iter.next();
                onlineUserMLog.setUserName(RedisHelper.getUname(onlineUserMLog.getUid()));
                onlineUserMLogs.add(onlineUserMLog);
            } catch (Exception e) {
                logger.error("获取OnlineUserMLog本月排行榜失败", e);
            }
        }
        if (onlineUserMLogs.size() == 0) {
            return null;
        }
        return onlineUserMLogs;
    }

    @Override
    public List<OnlineUserMLog> getUserOnlineDetail(long onlineType, String time, long uid, long partyId, int page, int rows) throws Exception {
        List<OnlineUserMLog> onlineUserMLogs = new ArrayList<>();
        if (!StringUtils.isNotBlank(time)) {
            time = DateUtil.getCurrDateTime();
        }
        String tableName = getOnlineUserDLogTable(DateUtil.getDateByString(time));
        StringBuilder sql = new StringBuilder();
        if (onlineType == 1) {
            tableName = userMlogTablename(DateUtil.getDateByString(time));
            sql.append(" select id,uid,party_id,org_id,org_code,sum(second) second,day,state from ").append(tableName).append(" where 1 = 1 ");
        } else {
            sql.append(" select id,uid,party_id,org_id,org_code,sum(second) second,start_time day,state from ").append(tableName).append(" where 1 = 1 ");
        }
        if (NumberUtils.isNotNullOrZero(uid)) {
            sql.append(" and uid=").append(uid);
        }
        if (NumberUtils.isNotNullOrZero(partyId)) {
            sql.append(" and party_id=").append(partyId);
        }
        sql.append(" GROUP BY uid ORDER BY second desc");
        List locationDataList = onlineUserMLogDao.findEntityBySql(sql.toString(), null, OnlineUserMLog.class, page, rows);
        for (Iterator iter = locationDataList.iterator(); iter.hasNext(); ) {
            try {
                OnlineUserMLog onlineUserMLog = (OnlineUserMLog) iter.next();
                onlineUserMLog.setUserName(RedisHelper.getUname(onlineUserMLog.getUid()));
                onlineUserMLogs.add(onlineUserMLog);
            } catch (Exception e) {
                logger.error("获取OnlineUserMLog当天排行榜失败", e);
            }
        }
        if (onlineUserMLogs.size() == 0) {
            return null;
        }
        return onlineUserMLogs;
    }

    @Override
    public long getUserOnlineDetailCount(long onlineType, String time, long uid, long partyId) throws Exception {
        if (!StringUtils.isNotBlank(time)) {
            time = DateUtil.getCurrDateTime();
        }
        String tableName = getOnlineUserDLogTable(DateUtil.getDateByString(time));
        if (onlineType == 1) {
            tableName = userMlogTablename(DateUtil.getDateByString(time));
        }
        StringBuilder sql = new StringBuilder();
        sql.append(" select count(*) from( select count(*) from ").append(tableName).append(" where 1 = 1 ");
        if (NumberUtils.isNotNullOrZero(uid)) {
            sql.append(" and uid=").append(uid);
        }
        if (NumberUtils.isNotNullOrZero(partyId)) {
            sql.append(" and party_id=").append(partyId);
        }
        sql.append(" GROUP BY uid) t");
        BigInteger count = onlineUserMLogDao.countBySql(sql.toString());
        if (count != null) {
            return count.longValue();
        }
        return 0;
    }

    @Override
    public List<OnlineUserDLog> getOnlineUserDLogByUid(long uid, String time) throws Exception {
        List<OnlineUserDLog> onlineUserDLogs = new ArrayList<>();
        if (!StringUtils.isNotBlank(time)) {
            time = DateUtil.getCurrDateTime();
        }
        String tableName = getOnlineUserDLogTable(DateUtil.getDateByString(time));
        StringBuilder sql = new StringBuilder();
        sql.append(" select * from ").append(tableName).append(" where state = 1 ");
        if (NumberUtils.isNotNullOrZero(uid)) {
            sql.append(" and uid=").append(uid);
        }
        sql.append(" ORDER BY id desc");
        List locationDataList = onlineUserDLogDao.findEntityBySql(sql.toString(), null, OnlineUserDLog.class);
        for (Iterator iter = locationDataList.iterator(); iter.hasNext(); ) {
            try {
                OnlineUserDLog onlineUserDLog = (OnlineUserDLog) iter.next();
                onlineUserDLogs.add(onlineUserDLog);
            } catch (Exception e) {
                logger.error("获取onlineUserDLog数据异常", e);
            }
        }
        if (onlineUserDLogs.size() == 0) {
            return null;
        }
        return onlineUserDLogs;
    }

    @Override
    public List<OnlineUserMLog> getOnlineUserMLogByUid(long uid, String time) throws Exception {
        List<OnlineUserMLog> onlineUserMLogs = new ArrayList<>();
        if (!StringUtils.isNotBlank(time)) {
            time = DateUtil.getCurrDateTime();
        }
        String tableName = userMlogTablename(DateUtil.getDateByString(time));
        StringBuilder sql = new StringBuilder();
        sql.append(" select * from ").append(tableName).append(" where state = 1 ");
        if (NumberUtils.isNotNullOrZero(uid)) {
            sql.append(" and uid=").append(uid);
        }
        sql.append(" ORDER BY id desc");
        List locationDataList = onlineUserMLogDao.findEntityBySql(sql.toString(), null, OnlineUserMLog.class);
        for (Iterator iter = locationDataList.iterator(); iter.hasNext(); ) {
            try {
                OnlineUserMLog onlineUserMLog = (OnlineUserMLog) iter.next();
                onlineUserMLogs.add(onlineUserMLog);
            } catch (Exception e) {
                logger.error("获取onlineUserDLog数据异常", e);
            }
        }
        if (onlineUserMLogs.size() == 0) {
            return null;
        }
        return onlineUserMLogs;
    }


}
